<template>
  <div>
    <!-- 图片上传标题 -->
    <div style="margin: 16px 0; font-weight: 600;">
      {{ title }} 
      <span v-if="!readonly" style="color:#909399; font-weight: normal;">最多上传{{ maxCount }}张，单张不大于{{ maxSize }}MB。</span>
    </div>
    
    <!-- 图片上传组件 -->
    <el-upload
      v-if="!readonly"
      :action="uploadUrl"
      :headers="uploadHeaders"
      :file-list="fileList"
      :on-success="handleUploadSuccess"
      :on-error="handleUploadError"
      :on-remove="handleUploadRemove"
      :before-upload="beforeUpload"
      list-type="picture-card"
      :limit="maxCount"
      accept="image/*"
    >
      <i class="el-icon-plus"></i>
    </el-upload>
    
    <!-- 只读模式：仅显示图片 -->
    <div v-else class="image-gallery-readonly">
      <div 
        v-for="(image, index) in fileList" 
        :key="index" 
        class="image-item-readonly"
        @click="previewImage(image.url)"
      >
        <img :src="image.url" :alt="image.name || `图片${index + 1}`" />
        <div class="image-overlay">
          <i class="el-icon-zoom-in"></i>
        </div>
      </div>
      <div v-if="!fileList || fileList.length === 0" class="no-images">
        <i class="el-icon-picture-outline"></i>
        <p>暂无图片</p>
      </div>
    </div>
  </div>
</template>

<script>
import { getToken } from "@/utils/auth";

export default {
  name: "ImageUpload",
  props: {
    // 图片文件列表
    value: {
      type: Array,
      default: () => []
    },
    // 上传标题
    title: {
      type: String,
      default: "图片"
    },
    // 最大上传数量
    maxCount: {
      type: Number,
      default: 5
    },
    // 最大文件大小(MB)
    maxSize: {
      type: Number,
      default: 2
    },
    // 上传接口地址（MinIO上传）
    uploadUrl: {
      type: String,
      default: () => {
        // 确保有默认值
        const baseApi = process.env.VUE_APP_BASE_API || '/dev-api'
        
        // 使用MinIO上传
        return baseApi + '/minio/upload'
      }
    },
    // 只读模式
    readonly: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      uploadHeaders: { Authorization: 'Bearer ' + getToken() }
    }
  },
  computed: {
    fileList: {
      get() {
        return this.value || []
      },
      set(val) {
        this.$emit('input', val)
      }
    }
  },
  methods: {
    // 将后端存储路径或相对路径转为可预览的HTTP URL
    toPreviewUrl(path) {
      if (!path) return ''
      let s = String(path)
      if (/^https?:\/\//i.test(s)) return s
      
      // MinIO 图片显示地址配置
      const minioBaseUrl = 'https://io.brightholdings.cn/smart-maintenance/'
      
      // 如果是MinIO存储的图片，直接拼接MinIO地址
      if (s && !s.startsWith('http')) {
        // 移除可能存在的本地路径前缀
        let cleanPath = s
        if (s.startsWith('/profile/upload/')) {
          cleanPath = s.substring('/profile/upload/'.length)
        } else if (s.startsWith('profile/upload/')) {
          cleanPath = s.substring('profile/upload/'.length)
        }
        // 确保路径正确拼接
        return minioBaseUrl + cleanPath
      }
      
      // 兼容 Windows 路径分隔符
      s = s.replace(/\\/g, '/')
      const lower = s.toLowerCase()
      const base = (process.env.VUE_APP_BASE_API || '').replace(/\/+$/, '')
      
      // 处理URL编码，避免重复编码
      const join = (p) => {
        const fullPath = base + (p.startsWith('/') ? p : '/' + p)
        // 如果路径已经包含编码字符，直接返回
        if (fullPath.includes('%')) {
          return fullPath
        }
        // 对路径进行编码，处理中文字符
        try {
          const urlObj = new URL(fullPath, window.location.origin);
          const pathParts = urlObj.pathname.split('/');
          const encodedPath = pathParts.map(part => {
            if (part && !part.includes('%')) {
              return encodeURIComponent(part);
            }
            return part;
          }).join('/');
          return urlObj.origin + encodedPath;
        } catch (e) {
          // 如果URL解析失败，使用简单的编码方式
          const parts = fullPath.split('/');
          const encodedParts = parts.map(part => {
            if (part && !part.includes('%') && /[\u4e00-\u9fa5]/.test(part)) {
              return encodeURIComponent(part);
            }
            return part;
          });
          return encodedParts.join('/');
        }
      }
      
      // 约定：磁盘路径包含 /upload/，RuoYi 静态映射通常是 /profile/** -> {uploadPath}
      const idx = lower.indexOf('/upload/')
      if (idx >= 0) {
        const suffix = s.substring(idx) // /upload/2025/09/26/xxx.png
        return join('/profile' + suffix)
      }
      // 若后端返回的是相对文件名
      if (lower.startsWith('profile/')) {
        return join('/' + s)
      }
      if (lower.startsWith('upload/')) {
        return join('/profile/' + s)
      }
      // 若仅有日期层级（例如 2025/09/26/xxx.png 或 2025\\09\\26\\xxx.png）
      if (/^\d{4}[\\/]\d{2}[\\/]\d{2}[\\/]/.test(s)) {
        const normalized = s.replace(/\\/g, '/')
        return join('/profile/upload/' + normalized)
      }
      // 兜底直接拼接
      return join('/' + s.replace(/^\//, ''))
    },
    
    // 上传前检查
    beforeUpload(file) {
      const ok = file.type.startsWith('image/') && file.size / 1024 / 1024 < this.maxSize
      if (!ok) this.$message.error(`仅支持图片且小于${this.maxSize}MB`)
      return ok
    },
    
    // 上传成功
    handleUploadSuccess(response, file, fileList) {
      if (response.code === 200) {
        // 后端通常返回 { url, fileName }，其中 fileName 是相对存储路径（建议入库），url 为可访问地址
        const stored = response.fileName || (response.data && response.data.fileName) || response.url || file.url
        const preview = this.toPreviewUrl(stored)
        // 将当前文件补充 url 与 rawName
        const mapped = fileList.map(f => {
          const raw = f.rawName || f.response?.fileName || f.url
          return { name: f.name, url: this.toPreviewUrl(raw || f.url), rawName: raw }
        })
        // 替换当前文件项（避免旧值无 rawName）
        if (!mapped.find(m => m.name === file.name)) {
          mapped.push({ name: file.name, url: preview, rawName: stored })
        }
        this.fileList = mapped
        this.$emit('success', response, file, fileList)
      } else {
        // 上传失败
        this.handleUploadError(response, file, fileList)
      }
    },
    
    // 上传失败处理
    handleUploadError(response, file, fileList) {
      console.error('MinIO上传失败:', response)
      this.$message.error('文件上传失败：' + (response.msg || 'MinIO服务不可用'))
    },
    
    // 移除图片
    handleUploadRemove(file, fileList) {
      this.fileList = fileList.map(f => ({ name: f.name, url: f.url, rawName: f.rawName }))
      this.$emit('remove', file, fileList)
    },
    
    // 从URL数组初始化文件列表（用于编辑时回显）
    initFromUrls(urls) {
      if (!urls || !Array.isArray(urls)) {
        this.fileList = []
        return
      }
      
      this.fileList = urls.map(u => {
        const url = this.toPreviewUrl(u)
        const name = (String(u || '').replace(/\\\\/g,'/').split('/').pop()) || '图片'
        // 保留原始存储值到 raw 字段，便于提交
        return { name, url, rawName: u }
      })
    },
    
    // 获取存储URL列表（用于提交到后端）
    getStoredUrls() {
      return (this.fileList || []).map(f => f.rawName || f.url).filter(Boolean)
    },
    
    // 预览图片
    previewImage(url) {
      if (!url) return
      // 使用Element UI的图片预览功能
      const images = this.fileList.map(f => f.url).filter(Boolean)
      const index = this.fileList.findIndex(f => f.url === url)
      
      // 创建预览元素
      const previewEl = document.createElement('div')
      previewEl.innerHTML = `
        <div style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 9999; display: flex; align-items: center; justify-content: center;">
          <div style="position: relative; max-width: 90%; max-height: 90%;">
            <img src="${url}" style="max-width: 100%; max-height: 100%; object-fit: contain;" />
            <div style="position: absolute; top: 20px; right: 20px; color: white; font-size: 24px; cursor: pointer;" onclick="this.parentElement.parentElement.remove()">×</div>
          </div>
        </div>
      `
      document.body.appendChild(previewEl)
      
      // 点击背景关闭
      previewEl.addEventListener('click', (e) => {
        if (e.target === previewEl) {
          document.body.removeChild(previewEl)
        }
      })
    }
  }
}
</script>

<style scoped>
.el-upload--picture-card {
  width: 100px;
  height: 100px;
  line-height: 100px;
}

.el-upload-list--picture-card .el-upload-list__item {
  width: 100px;
  height: 100px;
}

/* 只读模式样式 */
.image-gallery-readonly {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.image-item-readonly {
  position: relative;
  width: 100px;
  height: 100px;
  border: 1px solid #dcdfe6;
  border-radius: 6px;
  overflow: hidden;
  cursor: pointer;
  transition: all 0.3s;
}

.image-item-readonly:hover {
  border-color: #409eff;
  transform: scale(1.05);
}

.image-item-readonly img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.image-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.3s;
}

.image-item-readonly:hover .image-overlay {
  opacity: 1;
}

.image-overlay i {
  color: white;
  font-size: 20px;
}

.no-images {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100px;
  height: 100px;
  border: 1px dashed #dcdfe6;
  border-radius: 6px;
  color: #909399;
}

.no-images i {
  font-size: 24px;
  margin-bottom: 8px;
}

.no-images p {
  margin: 0;
  font-size: 12px;
}
</style>
